//package com.dfs.parent.gateway.filter;
//
//
//import com.dfs.parent.common.core.constant.GrayConstant;
//import com.dfs.parent.common.core.context.GrayContextHolder;
//import com.dfs.parent.gateway.loadbalancer.GrayLoadBalancer;
//import com.dfs.parent.gateway.props.GrayAppointProperties;
//import com.dfs.parent.gateway.props.GrayBatchProperties;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.cloud.client.ServiceInstance;
//import org.springframework.cloud.client.loadbalancer.*;
//import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
//import org.springframework.cloud.gateway.support.DelegatingServiceInstance;
//import org.springframework.cloud.gateway.support.NotFoundException;
//import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
//import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
//import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Mono;
//
//import java.net.URI;
//import java.util.Map;
//import java.util.Set;
//
//
///**
// * @Description TODO
// * @Author dahong
// * @Date 2024/2/18 08:02
// */
//@Slf4j
//public class GrayReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter {
//    private static final String LB = "lb";
//    private GatewayLoadBalancerProperties properties;
//    private LoadBalancerClientFactory clientFactory;
//    private  GrayAppointProperties grayAppointProperties;
//    private  GrayBatchProperties grayBatchProperties;
//
//
//
//    public GrayReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, GatewayLoadBalancerProperties properties
//            ,GrayBatchProperties grayBatchProperties,GrayAppointProperties grayAppointProperties) {
//        super(clientFactory, properties);
//        this.properties = properties;
//        this.clientFactory = clientFactory;
//        this.grayBatchProperties = grayBatchProperties;
//        this.grayAppointProperties = grayAppointProperties;
//    }
//
//
//    @Override
//    public int getOrder() {
//        return ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
//    }
//
//    @Override
//    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
//        String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
//        //判断url 前缀 如不是lb开头的就进行下一个过滤器
//        if (url == null || (!LB.equals(url.getScheme()) && !LB.equals(schemePrefix))) {
//            return chain.filter(exchange);
//        }
//        // preserve the original url
//        ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
//        if (log.isTraceEnabled()) {
//            log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
//        }
//        URI requestUri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
//        String serviceId = requestUri.getHost();
//        Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
//                .getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
//                        RequestDataContext.class, ResponseData.class, ServiceInstance.class);
//        DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(
//                new RequestDataContext(new RequestData(exchange.getRequest()), getHint(serviceId)));
//        LoadBalancerProperties loadBalancerProperties = this.clientFactory.getProperties(serviceId);
//        // 这里呢会进行调用真正的负载均衡
//        return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {
//            if (!response.hasServer()) {
//                supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
//                        .onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response)));
//                throw NotFoundException.create(properties.isUse404(), "Unable to find instance for " + url.getHost());
//            }
//
//            ServiceInstance retrievedInstance = (ServiceInstance)response.getServer();
//            URI uri = exchange.getRequest().getURI();
//            String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
//            if (schemePrefix != null) {
//                overrideScheme = url.getScheme();
//            }
//
//            DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance, overrideScheme);
//            URI requestUrl = this.reconstructURI(serviceInstance, uri);
//            if (log.isTraceEnabled()) {
//                log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
//            }
//
//            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
//            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);
//
//            if(GrayConstant.GRAY_TAG_VALUE_TRUE.equals(GrayContextHolder.getGrayTag())) {
//                //向headers请求头添加gray
//                ServerHttpRequest grayRequest = exchange.getRequest().mutate()
//                        .header(GrayConstant.GRAY_TAG, GrayConstant.GRAY_TAG_VALUE_TRUE)
//                        .build();
//                exchange.mutate().request(grayRequest).build();
//                GrayContextHolder.remove();
//            }
//
//            supportedLifecycleProcessors.forEach((lifecycle) -> {
//                lifecycle.onStartRequest(lbRequest, response);
//            });
//        }).then(chain.filter(exchange)).doOnError(throwable -> {
//            supportedLifecycleProcessors.forEach(lifecycle -> {
//                lifecycle.onComplete(new CompletionContext(CompletionContext.Status.FAILED, throwable, lbRequest, (Response)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR)));
//            });
//        }).doOnSuccess((aVoid) -> {
//            supportedLifecycleProcessors.forEach((lifecycle) -> {
//                lifecycle.onComplete(new CompletionContext(CompletionContext.Status.SUCCESS, lbRequest, (Response)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR), this.buildResponseData(exchange, loadBalancerProperties.isUseRawStatusCodeInResponseData())));
//            });
//        });
//    }
//    private ResponseData buildResponseData(ServerWebExchange exchange, boolean useRawStatusCodes) {
//        return useRawStatusCodes ? new ResponseData(new RequestData(exchange.getRequest()), exchange.getResponse()) : new ResponseData(exchange.getResponse(), new RequestData(exchange.getRequest()));
//    }
//
//    protected URI reconstructURI(ServiceInstance serviceInstance, URI original) {
//        return LoadBalancerUriTools.reconstructURI(serviceInstance, original);
//    }
//    private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId, Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {
//        // 修改 直接创建 GrayLoadBalancer 对象
//        GrayLoadBalancer loadBalancer = new GrayLoadBalancer(clientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId,grayBatchProperties,grayAppointProperties);
//        if (loadBalancer == null) {
//            throw new NotFoundException("No loadbalancer available for " + serviceId);
//        } else {
//            supportedLifecycleProcessors.forEach((lifecycle) -> {
//                lifecycle.onStart(lbRequest);
//            });
//            return loadBalancer.choose(lbRequest);
//        }
//    }
//
//    private String getHint(String serviceId) {
//        LoadBalancerProperties loadBalancerProperties = this.clientFactory.getProperties(serviceId);
//        Map<String, String> hints = loadBalancerProperties.getHint();
//        String defaultHint = (String)hints.getOrDefault("default", "default");
//        String hintPropertyValue = (String)hints.get(serviceId);
//        return hintPropertyValue != null ? hintPropertyValue : defaultHint;
//    }
//}
